//== SAGITTARIUS ============================================================================

//== FILEDOC =========================================================================

/** @file lsegalloc.h
  * @brief Memory pool to hopefully speed up the many allocations done by the lexer
  * @details It may also have the nice side effect of reducing the total memory usage,
  * as the lexer needs to create redundant copies of data to satisfy lifetime constraints
  */

//== BEGINNING OF CODE ===============================================================

#ifndef __SAGUTTARUIS__LSEGALLOC__H_
#define __SAGUTTARUIS__LSEGALLOC__H_

//== INCLUDES ========================================================================

#include "sagittarius/core/SagittariusCore.h"
#include <stddef.h>

#if LX_USE_POOLALLOC
    //use this at the beginning of functions etc. to push a segment onto the stack - all new
    //allocations will be done with this segment until it is popped back off
    #define LX_PUSH_SEG(segptr) lx_segstack_push(segptr)
    #define LX_POP_SEG()        lx_segstack_pop()

    //pushes & pops the state in addition to the above
	#if SAGITTARIUS_COMPILER != SAGITTARIUS_COMPILER_MSVC
		#define LX_PUSH_SAVE_SEG(segptr)   LX_PUSH_SEG(segptr); lx_segstate savedstate = lx_seg_savestate(segptr)
	#else
		#define LX_PUSH_SAVE_SEG(segptr)   lx_segstate savedstate; LX_PUSH_SEG(segptr); savedstate = lx_seg_savestate(segptr)
	#endif
    #define LX_POP_RESTORE_SEG()       lx_seg_restorestate(*lx_segstack_top, savedstate); LX_POP_SEG()
    
    #define LX_SEG_GET(depth) lx_segstack_get(depth)
#else
    #define LX_PUSH_SEG(segptr) 
    #define LX_POP_SEG()

    #define LX_PUSH_SAVE_SEG(segptr)
    #define LX_POP_RESTORE_SEG()
#endif

#ifdef __cplusplus
extern "C" {
#endif

//#define DO_LX_SEG_ALLOC

typedef struct {
    void* start;
    void* stop;
    void* p;
    //size_t len;
} lx_seg;

typedef struct __lx_seglink{
    lx_seg* seg;
    struct __lx_seglink* next;
} lx_seglink;

//this should be used with thread-local storage
typedef struct {
    lx_seglink *beg, *end;
    size_t step;
} lx_segcontext;

extern lx_segcontext** lx_segstack_top;

void lx_initsegctx(lx_segcontext* ctx);
void lx_destroysegctx(lx_segcontext* ctx);

void* lx_segalloc(lx_segcontext* ctx, size_t bytes);

//State save/restore
typedef struct {
    lx_seglink *end;
    void *p;
} lx_segstate;

lx_segstate lx_seg_savestate(lx_segcontext* ctx);
void lx_seg_restorestate(lx_segcontext* ctx, lx_segstate state);

//top-of-stack functions
extern lx_segcontext lx_myseg; //TODO: make thread-local
extern lx_segcontext lx_tmpseg; //TODO: make thread-local

void* lx_alloc(size_t bytes);
lx_segstate lx_alloc_savestate();
void lx_alloc_restorestate(lx_segstate state);

//-- Stack functions --//
void lx_segstack_push(lx_segcontext* ctxptr);
lx_segcontext* lx_segstack_pop();
lx_segcontext* lx_segstack_get(uint32 depth);

/*void* lx_tmpalloc(size_t bytes);
lx_segstate lx_tmpsave();
void lx_tmprestore(lx_segstate state);*/

#ifdef __cplusplus
}//extern "C"
#endif

#endif
